#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <fstream>
#include <mutex>
#include <boost/algorithm/string.hpp>
#include "cppjieba/Jieba.hpp"
#include "log.hpp"

using std::string;
using std::vector;
using std::unordered_map;

/* 
    这是一个工具集
    class file_util   -> 根据文件路径，读取文件所有内容
    class string_util -> 根据分隔符，对字符串进行分隔
    jieba_util        -> 去暂停词及内容分词功能
 */
namespace ns_util
{
    class file_util
    {
        public:
            static bool ReadFile(const string& file_path,string* file_content)
            {
                std::ifstream in(file_path,std::ios::in);

                if(!in.is_open())
                {
                    string log_message(file_path);
                    log_message += " open fail";
                    LOG(ERROR,log_message);

                   //std::cerr << file_path << " open fail" << std::endl;

                    return false;
                }

                string line_content;
                while(std::getline(in,line_content))
                {
                    *file_content += line_content;
                }
                in.close();

                return true;
            }
    };

    class string_util
    {
        public:
            /* split函数的第四个形参默认值为token_compress_off, token_compress_on表示进行压缩，即多个连续分隔符作为一个分隔符*/
            static void Split(const string& src_string,vector<string>* output,const string& separator)
            {
                boost::split(*output,src_string,boost::is_any_of(separator),boost::token_compress_on);
            }
    };
    
    const char* const DICT_PATH = "./dict/jieba.dict.utf8";
    const char* const HMM_PATH = "./dict/hmm_model.utf8";
    const char* const USER_DICT_PATH = "./dict/user.dict.utf8";
    const char* const IDF_PATH = "./dict/idf.utf8";
    const char* const STOP_WORDS_PATH = "./dict/stop_words.utf8";

    /* 单例模式 懒汉版本 */
    class jieba_util
    {
        private:
            cppjieba::Jieba _jieba;
            unordered_map<string, bool> _stop_words;
            static std::mutex _mtx; 
            static jieba_util* _instance;

            jieba_util()
                : _jieba(DICT_PATH, HMM_PATH, USER_DICT_PATH, IDF_PATH, STOP_WORDS_PATH)
            {
               
            }
            
            jieba_util(const jieba_util& obj) = delete;
            jieba_util& operator=(const jieba_util& obj) = delete;    
            
            void InitJiebaUtil()
            {
                std::ifstream in(STOP_WORDS_PATH);
                if(!in.is_open())
                {
                    string log_message(STOP_WORDS_PATH);
                    log_message += " open fail";
                    LOG(ERROR,log_message);

                    return;
                }

                string line_content;
                while(std::getline(in, line_content))
                {
                    _stop_words.insert({line_content, true});
                }

                in.close();
            }

            /* 
                对内容进行分词，并且会去掉暂停词
                说明：由于需要去掉暂停词，所以在构建倒排索引时速度会很慢
                     但是索引构建好，后续进行搜索服务时效率会提高
            */
            void _CutString(const string &src_str,vector<string>* out_words)
            {
                _jieba.CutForSearch(src_str,*out_words);
                for(auto iter = out_words->begin();iter!=out_words->end();)
                {
                    auto iter_res = _stop_words.find(*iter);
                    if(iter_res != _stop_words.end())
                    {
                        iter = out_words->erase(iter); // 防止迭代器失效
                    }
                    else
                    {
                        iter++;
                    }
                }
            }
        
        public:
            static jieba_util* GetInstance()
            {
                if(nullptr == _instance)
                {
                    _mtx.lock();
                    if(nullptr == _instance)
                    {
                        _instance = new jieba_util();
                        _instance->InitJiebaUtil();
                    }
                    _mtx.unlock();
                }

                return _instance;
            }

            static void CutString(const string &src_str,vector<string> *out_words)
            {
                GetInstance()->_CutString(src_str,out_words);
            }
    };
    jieba_util* jieba_util::_instance = nullptr;    
    std::mutex jieba_util::_mtx;

}